#pragma once
#include <vector>

template<typename T>
class Matrix
{
private:
	T* data = nullptr;
public:
	int row,col;
	Matrix(int row, int col, const std::vector<T> dataInit);
	Matrix(int row, int col);
	Matrix(const Matrix<T>& other);
	T* operator[](int row);
	T& get(int row, int col);
	~Matrix();
};

template<typename T>
Matrix<T>::Matrix(int row, int col, const std::vector<T> dataInit) :row(row), col(col) {
	if (dataInit.size() != row * col)
	{
		throw "dataInit size is not equal to row * col";
	}
	this->data = new T[row * col];
	for (size_t i = 0; i < dataInit.size(); i++)
	{
		this->data[i] = dataInit[i];
	}
}
template<typename T>
Matrix<T>::Matrix(int row, int col) :row(row), col(col) {
	int64_t arraySize = static_cast<int64_t>(row) * col;
	this->data = new T[arraySize];
}


template<typename T>
Matrix<T>::Matrix(const Matrix<T>& other) :row(other.row), col(other.col) {
	for (size_t i = 0; i < other.row * other.col; i++)
	{
		this->data[i] = other.data[i];
	}
}

template<typename T>
T* Matrix<T>::operator[](int row) {
	if (row > this->row || row < 0)
	{
		throw "row index out of range";
	}
	return this->data + (row * this->col);
}

template<typename T>
T& Matrix<T>::get(int row, int col) {
	if (row > this->row || row < 0)
	{
		throw "row index out of range";
	}
	if (col > this->col || col < 0)
	{
		throw "col index out of range";
	}
	return this->data[row * this->col + col];
}

template<typename T>
Matrix<T>::~Matrix() {
	delete[] data;
}